home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / FaxServer.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  46KB  |  1,630 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/FaxServer.c++,v 1.141 1994/04/10 05:06:53 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <osfcn.h>
  26. #include <ctype.h>
  27. #include <termios.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <errno.h>
  31. #include <signal.h>
  32. #include <stdlib.h>
  33. #include <sys/param.h>
  34. #include <sys/stat.h>
  35. #include <sys/time.h>
  36. #include <sys/ioctl.h>
  37. #include <sys/file.h>
  38.  
  39. #include <Dispatch/dispatcher.h>
  40.  
  41. #include "t.30.h"
  42. #include "tiffio.h"
  43. #include "FaxServer.h"
  44. #include "faxServerApp.h"
  45. #include "FaxRecvInfo.h"
  46. #include "RegExArray.h"
  47. #include "Getty.h"
  48. #include "UUCPLock.h"
  49. #include "DialRules.h"
  50. #include "config.h"
  51.  
  52. #ifndef MAXHOSTNAMELEN
  53. #define    MAXHOSTNAMELEN    64
  54. #endif
  55. #ifndef O_NOCTTY
  56. #define    O_NOCTTY    0        // no POSIX O_NOCTTY support
  57. #endif
  58.  
  59. /*
  60.  * FAX Modem Server.
  61.  */
  62.  
  63. extern    void fxFatal(const char* va_alist ...);
  64.  
  65. int FaxServer::pageWidthCodes[8] = {
  66.     1728,    // 1728 in 215 mm line
  67.     2048,    // 2048 in 255 mm line
  68.     2432,    // 2432 in 303 mm line
  69.     1216,    // 1216 in 151 mm line
  70.     864,    // 864 in 107 mm line
  71.     1728,    // undefined
  72.     1728,    // undefined
  73.     1728,    // undefined
  74. };
  75. int FaxServer::pageLengthCodes[4] = {
  76.     297,    // A4 paper
  77.     364,    // B4 paper
  78.     -1,        // unlimited
  79.     -1        // undefined
  80. };
  81.  
  82. // map FaxModem::BaudRate to numeric value
  83. static u_int baudRates[] = {
  84.     0,        // BR0
  85.     300,    // BR300
  86.     1200,    // BR1200
  87.     2400,    // BR2400
  88.     4800,    // BR4800
  89.     9600,    // BR9600
  90.     19200,    // BR19200
  91.     38400,    // BR38400
  92.     57600,    // BR57600
  93. };
  94.  
  95. FaxServer::FaxServer(faxServerApp* a, const fxStr& devName, const fxStr& devID)
  96.     : modemDevice(devName), modemDevID(devID)
  97. {
  98.     state = BASE;
  99.     app = a;
  100.     getty = NULL;
  101.     statusFile = NULL;
  102.     abortCall = FALSE;
  103.     deduceComplain = TRUE;        // first failure causes complaint
  104.     modemFd = -1;
  105.     modemLock = OSnewUUCPLock(devName);
  106.     modem = NULL;
  107.     lastConfigModTime = 0;
  108.     speakerVolume = FaxModem::QUIET;    // default speaker volume
  109.     curRate = FaxModem::BR0;        // unspecified baud rate
  110.     ringsBeforeAnswer = 0;        // default is not to answer phone
  111.     noCarrierRetrys = 1;        // retry sends once if no carrier
  112.     recvFileMode = 0600;        // default protection mode
  113.     deviceMode = 0600;            // default mode for modem device
  114.     logMode = 0600;            // default mode for log files
  115.     requeueTTS[FaxModem::OK]        = 0;
  116.     requeueTTS[FaxModem::BUSY]        = FAX_REQBUSY;
  117.     requeueTTS[FaxModem::NOCARRIER]    = FAX_REQUEUE;
  118.     requeueTTS[FaxModem::NOANSWER]    = FAX_REQUEUE;
  119.     requeueTTS[FaxModem::NODIALTONE]    = FAX_REQUEUE;
  120.     requeueTTS[FaxModem::ERROR]        = FAX_REQUEUE;
  121.     requeueTTS[FaxModem::FAILURE]    = FAX_REQUEUE;
  122.     requeueProto = FAX_REQPROTO;
  123.     requeueOther = FAX_REQUEUE;
  124.     pollModemWait = 30;            // default polling every 30 seconds
  125.     pollLockWait = 30;            // default polling every 30 seconds
  126.     tracingLevel = FAXTRACE_SERVER;
  127.     logTracingLevel = FAXTRACE_SERVER;
  128.     tracingMask = FAXTRACE_MODEMIO|FAXTRACE_TIMEOUTS;
  129.     adaptiveAnswer = FALSE;        // don't answer data if fax answer fails
  130.     answerBias = -1;
  131.     setAnswerRotary("any");
  132.     rcvNext = rcvCC = 0;
  133.     lastPatModTime = 0;
  134.     tsiPats = NULL;
  135.     log = NULL;
  136.     dialRules = NULL;
  137. }
  138.  
  139. FaxServer::~FaxServer()
  140. {
  141.     close();
  142.     delete modemLock;
  143.     delete tsiPats;
  144.     delete getty;
  145.     delete log;
  146.     delete dialRules;
  147. }
  148.  
  149. /*
  150.  * Startup the server for the first time.
  151.  */
  152. void
  153. FaxServer::open()
  154. {
  155.     if (modemLock->lock()) {
  156.     fxBool modemReady = setupModem();
  157.     modemLock->unlock();
  158.     if (!modemReady)
  159.         changeState(MODEMWAIT, pollModemWait);
  160.     else
  161.         changeState(RUNNING, 0);
  162.     } else {
  163.     traceStatus(FAXTRACE_SERVER, "%s: Can not lock device.",
  164.         (char*) modemDevice);
  165.     changeState(LOCKWAIT, pollLockWait);
  166.     }
  167. }
  168.  
  169. /*
  170.  * Close down the server.
  171.  */
  172. void
  173. FaxServer::close()
  174. {
  175.     if (modemLock->lock()) {
  176.     if (modem)
  177.         modem->hangup();
  178.     discardModem(TRUE);
  179.     modemLock->unlock();
  180.     }
  181. }
  182.  
  183. /*
  184.  * Initialize the server from command line arguments.
  185.  */
  186. void
  187. FaxServer::initialize(int argc, char** argv)
  188. {
  189.     extern int optind, opterr;
  190.     extern char* optarg;
  191.     int c;
  192.     optind = 1;                // 'cuz we're using getopt twice
  193.     opterr = 0;
  194.     while ((c = getopt(argc, argv, "m:g:i:q:d1x")) != -1)
  195.     switch (c) {
  196.     case 'g':
  197.         if (*optarg == '\0')
  198.         fxFatal("No getty speed specified");
  199.         gettyArgs = optarg;
  200.         break;
  201.     case 'x':
  202.         tracingMask &= ~(FAXTRACE_MODEMIO|FAXTRACE_TIMEOUTS);
  203.         break;
  204.     }
  205.     TIFFSetErrorHandler(NULL);
  206.     TIFFSetWarningHandler(NULL);
  207.     updateTSIPatterns();
  208.     // setup server's status file
  209.     fxStr file(FAX_STATUSDIR);
  210.     file.append("/" | modemDevID);
  211.     statusFile = fopen(file, "w");
  212.     if (statusFile != NULL) {
  213. #if HAS_FCHMOD
  214.     fchmod(fileno(statusFile), 0644);
  215. #else
  216.     chmod((char*) file, 0644);
  217. #endif
  218.     setServerStatus("Initializing server");
  219.     }
  220.     hostname.resize(MAXHOSTNAMELEN);
  221.     if (gethostname((char*) hostname, MAXHOSTNAMELEN) == 0)
  222.     hostname.resize(strlen(hostname));
  223.     ::umask(077);            // keep all temp files private
  224. }
  225.  
  226. const char* FaxServer::stateNames[8] = {
  227.     "BASE",
  228.     "RUNNING",
  229.     "MODEMWAIT",
  230.     "LOCKWAIT",
  231.     "GETTYWAIT",
  232.     "SENDING",
  233.     "ANSWERING",
  234.     "RECEIVING"
  235. };
  236. const char* FaxServer::stateStatus[8] = {
  237.     "Initializing server and modem",        // BASE
  238.     "Running and idle",                // RUNNING
  239.     "Waiting for modem to come ready",        // MODEMWAIT
  240.     "Waiting for modem to come free",        // LOCKWAIT
  241.     "Waiting for login session to terminate",    // GETTYWAIT
  242.     "Sending facsimile",            // SENDING
  243.     "Answering the phone",            // ANSWERING
  244.     "Receiving facsimile",            // RECEIVING
  245. };
  246.  
  247. /*
  248.  * Change the server's state and, optionally,
  249.  * start a timer running for timeout seconds.
  250.  */
  251. void
  252. FaxServer::changeState(FaxServerState s, long timeout)
  253. {
  254.     if (s != state) {
  255.     if (timeout)
  256.         traceStatus(FAXTRACE_STATETRANS,
  257.         "STATE CHANGE: %s -> %s (timeout %ld)",
  258.         stateNames[state], stateNames[s], timeout);
  259.     else
  260.         traceStatus(FAXTRACE_STATETRANS, "STATE CHANGE: %s -> %s",
  261.         stateNames[state], stateNames[s]);
  262.     state = s;
  263.     setProcessPriority(state);
  264.     setServerStatus(stateStatus[state]);
  265.     if (s == RUNNING)
  266.         app->notifyModemReady();        // notify surrogate
  267.     }
  268.     if (timeout)
  269.     Dispatcher::instance().startTimer(timeout, 0, this);
  270. }
  271.  
  272. #ifdef sgi
  273. #include <sys/schedctl.h>
  274. /*
  275.  * When low latency is required, use a nondegrading process
  276.  * priority; otherwise just remove any nondegrading priority.
  277.  * Note that we assign a high nondegrading priority when sending,
  278.  * answering the telephone, or receiving.  We assume that if the
  279.  * incoming call spawns a getty process that the priority will
  280.  * be reset in the child before the getty is exec'd.
  281.  */
  282. static const int schedCtlParams[8][2] = {
  283.     { NDPRI, 0 },        // BASE
  284.     { NDPRI, 0 },        // RUNNING
  285.     { NDPRI, 0 },        // MODEMWAIT
  286.     { NDPRI, 0 },        // LOCKWAIT
  287.     { NDPRI, 0 },        // GETTYWAIT
  288.     { NDPRI, NDPHIMIN },    // SENDING
  289.     { NDPRI, NDPHIMIN },    // ANSWERING
  290.     { NDPRI, NDPHIMIN },    // RECEIVING
  291. };
  292. #elif svr4 
  293. extern "C" {
  294. #include <sys/priocntl.h>
  295. #include <sys/rtpriocntl.h>
  296. #include <sys/tspriocntl.h>
  297. }
  298. static struct SchedInfo {
  299.     const char*    clname;        // scheduling class name
  300.     int        params[3];    // scheduling class parameters
  301. } schedInfo[8] = {
  302.     { "TS", { TS_NOCHANGE, TS_NOCHANGE } },        // BASE
  303.     { "TS", { TS_NOCHANGE, TS_NOCHANGE } },        // RUNNING
  304.     { "TS", { TS_NOCHANGE, TS_NOCHANGE } },        // MODEMWAIT
  305.     { "TS", { TS_NOCHANGE, TS_NOCHANGE } },        // LOCKWAIT
  306.     { "TS", { TS_NOCHANGE, TS_NOCHANGE } },        // GETTYWAIT
  307.     { "RT", { RT_NOCHANGE, RT_NOCHANGE, RT_NOCHANGE } },// SENDING
  308.     { "RT", { RT_NOCHANGE, RT_NOCHANGE, RT_NOCHANGE } },// ANSWERING
  309.     { "RT", { RT_NOCHANGE, RT_NOCHANGE, RT_NOCHANGE } },// RECEIVING
  310. };
  311. #endif
  312.  
  313. void
  314. FaxServer::setProcessPriority(FaxServerState s)
  315. {
  316. #ifdef sgi
  317.     uid_t euid = geteuid();
  318.     if (seteuid(0) >= 0) {        // must be done as root
  319.     if (schedctl(schedCtlParams[s][0], 0, schedCtlParams[s][1]) < 0)
  320.         traceStatus(FAXTRACE_SERVER, "schedctl: %m");
  321.     if (seteuid(euid) < 0)        // restore previous effective uid
  322.         traceStatus(FAXTRACE_SERVER, "seteuid(%d): %m", euid);
  323.     } else
  324.     traceStatus(FAXTRACE_SERVER, "seteuid(root): %m");
  325. #elif svr4
  326.     uid_t euid = geteuid();
  327.     if (seteuid(0) >= 0) {        // must be done as root
  328.     const SchedInfo& si = schedInfo[s];
  329.     pcinfo_t pcinfo;
  330.     strcpy(pcinfo.pc_clname, si.clname);
  331.     if (priocntl((idtype_t)0, 0, PC_GETCID, (caddr_t)&pcinfo) >= 0) {
  332.         pcparms_t pcparms;
  333.         pcparms.pc_cid = pcinfo.pc_cid;
  334.         if (strcmp(si.clname,"RT") == 0) {
  335.         rtparms_t* rtp = (rtparms_t*) pcparms.pc_clparms;
  336.         rtp->rt_pri    = si.params[0];
  337.         rtp->rt_tqsecs    = (ulong) si.params[1];
  338.         rtp->rt_tqnsecs    = si.params[2];
  339.         } else {
  340.         tsparms_t* tsp = (tsparms_t*) pcparms.pc_clparms;
  341.         tsp->ts_uprilim    = si.params[0];
  342.         tsp->ts_upri    = si.params[1];
  343.         }
  344.         if (priocntl(P_PID, P_MYID, PC_SETPARMS, (caddr_t)&pcparms) < 0)
  345.         traceStatus(FAXTRACE_SERVER,
  346.             "Unable to set %s scheduling parameters: %m", si.clname);
  347.     } else
  348.         traceStatus(FAXTRACE_SERVER, "priocntl(%s): %m", si.clname);
  349.     if (seteuid(euid) < 0)        // restore previous effective uid
  350.         traceStatus(FAXTRACE_SERVER, "setreuid(%d): %m", euid);
  351.     } else
  352.     traceStatus(FAXTRACE_SERVER, "setreuid(root): %m");
  353. #endif
  354. }
  355.  
  356. /*
  357.  * Record the server status in the status file.
  358.  */
  359. void
  360. FaxServer::setServerStatus(const char* fmt, ...)
  361. {
  362.     if (statusFile != NULL) {    // NB: XXX workaround for YET ANOTHER gcc bug
  363.     flock(fileno(statusFile), LOCK_EX);
  364.     fseek(statusFile, 0L, 0);
  365.     ftruncate(fileno(statusFile), 0);
  366.     va_list ap;
  367.     va_start(ap, fmt);
  368.     vfprintf(statusFile, fmt, ap);
  369.     fprintf(statusFile, "\n");
  370.     fflush(statusFile);
  371.     flock(fileno(statusFile), LOCK_UN);
  372.     }
  373. }
  374.  
  375. /*
  376.  * Setup the modem; if needed.  Note that we reread
  377.  * the configuration file if it's been changed prior
  378.  * to setting up the modem.  This makes it easy to
  379.  * swap modems that need different configurations
  380.  * just by yanking the cable and then swapping the
  381.  * config file before hooking up the new modem.
  382.  */
  383. fxBool
  384. FaxServer::setupModem()
  385. {
  386.     /*
  387.      * Possibly reread the configuration file.  We
  388.      * always do this prior to setting up the modem
  389.      * so that someone can tweak the configuration file
  390.      * and have the server automatically select new
  391.      * modem configuration parameters (instead of
  392.      * requiring that the server be restarted).
  393.      */
  394.     fxStr file(FAX_CONFIG);
  395.     file.append("." | modemDevID);
  396.     if (restoreState(file) && modem)
  397.     discardModem(TRUE);
  398.     if (!modem) {
  399.     const char* dev = modemDevice;
  400.     if (!openDevice(dev))
  401.         return (FALSE);
  402.     /*
  403.      * Deduce modem type and setup configuration info.
  404.      * The deduceComplain cruft is just to reduce the
  405.      * noise in the log file when probing for a modem.
  406.      */
  407.     modem = FaxModem::deduceModem(*this, modemConfig);
  408.     if (!modem) {
  409.         discardModem(TRUE);
  410.         if (deduceComplain) {
  411.         traceStatus(FAXTRACE_SERVER,
  412.             "%s: Can not deduce modem type.", dev);
  413.         deduceComplain = FALSE;
  414.         }
  415.         return (FALSE);
  416.     } else {
  417.         deduceComplain = TRUE;
  418.         traceStatus(FAXTRACE_SERVER, "MODEM %s %s/%s",
  419.         (char*) modem->getManufacturer(),
  420.         (char*) modem->getModel(),
  421.         (char*) modem->getRevision());
  422.     }
  423.     } else
  424.     /*
  425.      * Reset the modem in case some other program
  426.      * went in and messed with the configuration.
  427.      */
  428.     modem->reset();
  429.     /*
  430.      * Most modem-related parameters are dealt with
  431.      * in the modem driver.  The speaker volume is
  432.      * kept in the fax server because it often gets
  433.      * changed on the fly.  The phone number has no
  434.      * business in the modem class.
  435.      */
  436.     modem->setSpeakerVolume(speakerVolume);
  437.     modem->setLID(canonicalizePhoneNumber(FAXNumber));
  438.     /*
  439.      * If the server is configured, listen for incoming calls.
  440.      */
  441.     setRingsBeforeAnswer(ringsBeforeAnswer);
  442.     return (TRUE);
  443. }
  444.  
  445. /*
  446.  * Open the tty device associated with the modem
  447.  * and change the device file to be owned by us
  448.  * and with a protected file mode.
  449.  */
  450. fxBool
  451. FaxServer::openDevice(const char* dev)
  452. {
  453.     /*
  454.      * Temporarily become root to open the device.
  455.      * Routines that call setupModem *must* first
  456.      * lock the device with the usual effective uid.
  457.      */
  458.     uid_t euid = geteuid();
  459.     if (seteuid(0) < 0) {
  460.      traceStatus(FAXTRACE_SERVER, "%s: seteuid root failed (%m)", dev);
  461.      return (FALSE);
  462.     }
  463. #ifdef O_NDELAY
  464.     /*
  465.      * Open device w/ O_NDELAY to bypass modem
  466.      * control signals, then turn off the flag bit.
  467.      */
  468.     modemFd = ::open(dev, O_RDWR|O_NDELAY|O_NOCTTY);
  469.     if (modemFd < 0) {
  470.     seteuid(euid);
  471.     traceStatus(FAXTRACE_SERVER, "%s: Can not open modem (%m)", dev);
  472.     return (FALSE);
  473.     }
  474.     int flags = fcntl(modemFd, F_GETFL, 0);
  475.     if (fcntl(modemFd, F_SETFL, flags &~ O_NDELAY) < 0) {
  476.      traceStatus(FAXTRACE_SERVER, "%s: fcntl: %m", dev);
  477.      ::close(modemFd), modemFd = -1;
  478.      return (FALSE);
  479.     }
  480. #else
  481.     startTimeout(3*1000);
  482.     modemFd = ::open(dev, O_RDWR);
  483.     stopTimeout("opening modem");
  484.     if (modemFd < 0) {
  485.     seteuid(euid);
  486.     traceStatus(FAXTRACE_SERVER,
  487.         (timeout ?
  488.         "%s: Can not open modem (timed out)." :
  489.         "%s: Can not open modem (%m)."),
  490.         dev, errno);
  491.     return (FALSE);
  492.     }
  493. #endif
  494.     /*
  495.      * NB: we stat and use the gid because passing -1
  496.      *     through the gid_t parameter in the prototype
  497.      *       causes it to get truncated to 65535.
  498.      */
  499.     struct stat sb;
  500.     (void) fstat(modemFd, &sb);
  501. #if HAS_FCHOWN
  502.     if (fchown(modemFd, UUCPLock::getUUCPUid(), sb.st_gid) < 0)
  503. #else
  504.     if (chown((char*) dev, UUCPLock::getUUCPUid(), sb.st_gid) < 0)
  505. #endif
  506.     traceStatus(FAXTRACE_SERVER, "%s: chown: %m", dev);
  507. #if HAS_FCHMOD
  508.     if (fchmod(modemFd, deviceMode) < 0)
  509. #else
  510.     if (chmod((char*) dev, deviceMode) < 0)
  511. #endif
  512.     traceStatus(FAXTRACE_SERVER, "%s: chmod: %m", dev);
  513.     seteuid(euid);
  514.     return (TRUE);
  515. }
  516.  
  517. fxBool
  518. FaxServer::reopenDevice()
  519. {
  520.     if (modemFd >= 0)
  521.     ::close(modemFd), modemFd = -1;
  522.     return openDevice(modemDevice);
  523. }
  524.  
  525. /*
  526.  * Discard any handle on the modem.
  527.  */
  528. void
  529. FaxServer::discardModem(fxBool dropDTR)
  530. {
  531.     if (modemFd >= 0) {
  532.     if (Dispatcher::instance().handler(modemFd, Dispatcher::ReadMask))
  533.         Dispatcher::instance().unlink(modemFd);
  534.     if (dropDTR)
  535.         (void) setDTR(FALSE);            // force hangup
  536.     ::close(modemFd), modemFd = -1;            // discard open file
  537.     }
  538.     delete modem, modem = NULL;
  539. }
  540.  
  541. /*
  542.  * Return true if a request has been made to abort
  543.  * the current session.  This is true if a previous
  544.  * abort request was made or if an external abort
  545.  * message is dispatched during our processing.
  546.  */
  547. fxBool
  548. FaxServer::abortRequested()
  549. {
  550. #if !defined(AIXV3) && !defined(hpux)
  551.     if (!abortCall) {
  552.     // poll for input so abort commands get processed
  553.     long sec = 0;
  554.     long usec = 0;
  555.     while (Dispatcher::instance().dispatch(sec,usec) && !abortCall)
  556.         ;
  557.     }
  558. #endif
  559.     return (abortCall);
  560. }
  561.  
  562. void
  563. FaxServer::abortSession()
  564. {
  565.     abortCall = TRUE;
  566.     traceStatus(FAXTRACE_SERVER, "ABORT: job abort requested");
  567. }
  568.  
  569. /*
  570.  * Dispatcher input ready routine.  This is usually called
  571.  * because the phone is ringing, but it can also be called
  572.  * when, for example, a process dials out on the modem.
  573.  */
  574. int
  575. FaxServer::inputReady(int)
  576. {
  577.     answerPhone(FaxModem::ANSTYPE_ANY, FALSE);
  578.     return (0);
  579. }
  580.  
  581. /*
  582.  * Dispatcher timer expired routine.  Perform the action
  583.  * associated with the server's state and, possible, transition
  584.  * to a new state.
  585.  */
  586. void
  587. FaxServer::timerExpired(long, long)
  588. {
  589.     switch (state) {
  590.     case MODEMWAIT:
  591.     case LOCKWAIT:
  592.     /*
  593.      * Waiting for modem to start working.  Retry setup
  594.      * and either change state or restart the timer.
  595.      * Note that we unlock the modem before we change
  596.      * our state to RUNNING after a modem setup so that
  597.      * any callback doesn't find the modem locked (and
  598.      * so cause jobs to be requeued).
  599.      */
  600.     if (modemLock->lock()) {
  601.         fxBool modemReady = setupModem();
  602.         modemLock->unlock();
  603.         if (modemReady)
  604.         changeState(RUNNING, 0);
  605.         else
  606.         changeState(MODEMWAIT, pollModemWait);
  607.     } else
  608.         changeState(LOCKWAIT, pollLockWait);
  609.     break;
  610.     }
  611. }
  612.  
  613. void
  614. FaxServer::childStatus(pid_t, int status)
  615. {
  616.     switch (state) {
  617.     case GETTYWAIT:
  618.     /*
  619.      * Waiting for getty/login process to terminate.
  620.      * Unlock the modem and reset the world because
  621.      * we discarded modem state when we started the getty.
  622.      */
  623.     traceStatus(FAXTRACE_SERVER, "GETTY: exit status %#o", status);
  624.     delete getty, getty = NULL;
  625.     modemLock->unlock();        // it's safe now to remove the lock
  626.     changeState(MODEMWAIT, 2);    // wait a touch for the modem to settle
  627.     break;
  628.     }
  629. }
  630.  
  631. /*
  632.  * Answer the telephone in response to data from the modem
  633.  * (e.g. a "RING" message) or an explicit command from the
  634.  * user (sending an "ANSWER" command through the FIFO).
  635.  */
  636. void
  637. FaxServer::answerPhone(AnswerType atype, fxBool force)
  638. {
  639.     if (modemLock->lock()) {
  640.     changeState(ANSWERING);
  641.     if (force || modem->waitForRings(ringsBeforeAnswer)) {
  642.         fxStr emsg;
  643.         fxStr canon(canonicalizePhoneNumber(FAXNumber));
  644.         log = new FaxMachineLog(canon, logMode);
  645.         /*
  646.          * If requested, rotate the way we answer the phone
  647.          * if the request type is "any".  This should probably
  648.          * only be used if the modem does not directly support
  649.          * adaptive-answer.
  650.          */
  651.         if (atype == FaxModem::ANSTYPE_ANY)
  652.         atype = answerRotary[answerRotor];
  653.         CallType ctype = modem->answerCall(atype, emsg);
  654.         fxBool waitForProcess;
  655.         fxBool callSetup = setupCall(atype, ctype, waitForProcess, emsg);
  656.         if (!callSetup && ctype == FaxModem::CALLTYPE_FAX && adaptiveAnswer) {
  657.         /*
  658.          * Status indicated a call from a fax machine, but we
  659.          * were unable to complete the initial handshake.
  660.          * If we are doing adaptive answer, immediately
  661.          * retry answering the call as data w/o hanging up
  662.          * the phone (note that this depends on characteristics
  663.          * of the local phone system).
  664.          */
  665.         atype = FaxModem::ANSTYPE_DATA;
  666.         ctype = modem->answerCall(atype, emsg);
  667.         callSetup = setupCall(atype, ctype, waitForProcess, emsg);
  668.         }
  669.         /*
  670.          * Call resolved.  If we were able to recognize the call
  671.          * type and setup a session, then reset the answer rotary
  672.          * state if there is a bias toward a specific answer type.
  673.          * Also, deal with call types that are processed through
  674.          * a subprocess, rather than within this process.  Otherwise,
  675.          * if the call failed, advance the rotor to the next answer
  676.          * type in preparation for the next call.
  677.          */
  678.         if (callSetup) {
  679.         if (answerBias >= 0)
  680.             answerRotor = answerBias;
  681.         /*
  682.          * Some calls are handled by starting up a subprocess
  683.          * that does the work.  For such calls we have to wait
  684.          * for the process to exit before we can remove the
  685.          * lock file and do related cleanup work.
  686.          */
  687.         if (waitForProcess)
  688.             return;
  689.         } else
  690.         answerRotor = (answerRotor+1) % answerRotorSize;
  691.         delete log, log = NULL;
  692.     } else
  693.         modemFlushInput();
  694.     /*
  695.      * Because some modems are impossible to safely hangup in the
  696.      * event of a problem, we force a close on the device so that
  697.      * the modem will see DTR go down and (hopefully) clean up any
  698.      * bad state its in.  We then immediately try to setup the modem
  699.      * again so that we can be ready to answer incoming calls again.
  700.      */
  701.     modem->hangup();
  702.     discardModem(TRUE);
  703.     fxBool modemReady = setupModem();
  704.     modemLock->unlock();
  705.     if (!modemReady)
  706.         changeState(MODEMWAIT, pollModemWait);
  707.     else
  708.         changeState(RUNNING);
  709.     } else {
  710.     /*
  711.      * The modem is in use to call out, or by way of an incoming
  712.      * call.  If we're not sending or receiving, discard our handle
  713.      * on the modem and change to MODEMWAIT state where we wait
  714.      * for the modem to come available again.
  715.      */
  716.     traceStatus(FAXTRACE_SERVER, "ANSWER: Can not lock modem device");
  717.     if (state != SENDING && state != ANSWERING) {
  718.         discardModem(FALSE);
  719.         changeState(LOCKWAIT, pollLockWait);
  720.     }
  721.     }
  722. }
  723.  
  724. /*
  725.  * Do setup after answering an incoming call.
  726.  */
  727. fxBool
  728. FaxServer::setupCall(AnswerType atype, CallType ctype, fxBool& waitForProcess,
  729.     fxStr& emsg)
  730. {
  731.     fxBool callSetup = FALSE;
  732.     waitForProcess = FALSE;
  733.  
  734.     switch (ctype) {
  735.     case FaxModem::CALLTYPE_FAX:
  736.     traceStatus(FAXTRACE_SERVER, "ANSWER: FAX CONNECTION");
  737.     callSetup = recvFax();
  738.     break;
  739.     case FaxModem::CALLTYPE_DATA:
  740.     traceStatus(FAXTRACE_SERVER, "ANSWER: DATA CONNECTION");
  741.     if (gettyArgs == "") {
  742.         traceStatus(FAXTRACE_SERVER,
  743.         "ANSWER: Data connections are not permitted");
  744.         break;
  745.     }
  746.     /*
  747.      * If call was answered using an adaptive-answering
  748.      * facility, then give the modem an opportunity to
  749.      * establish data services.
  750.      */
  751.     if (atype == FaxModem::ANSTYPE_ANY && !modem->dataService()) {
  752.         traceStatus(FAXTRACE_SERVER,
  753.         "ANSWER: Could not switch modem to data service");
  754.         break;
  755.     }
  756.     /*
  757.      * Fork and exec a getty process to handle the
  758.      * data connection.  Note that we return without
  759.      * removing our lock on the modem--this is done
  760.      * after we reap the child getty process to insure
  761.      * outgoing modem use is disallowed.
  762.      */
  763.     if (runGetty(gettyArgs)) {
  764.         delete log, log = NULL;
  765.         callSetup = TRUE;
  766.         waitForProcess = TRUE;
  767.     }
  768.     break;
  769.     case FaxModem::CALLTYPE_VOICE:
  770.     traceStatus(FAXTRACE_SERVER, "ANSWER: VOICE CONNECTION");
  771.     /*
  772.      * If call was answered using an adaptive-answering
  773.      * facility, then give the modem an opportunity to
  774.      * establish voice services.
  775.      */
  776.     if (atype == FaxModem::ANSTYPE_ANY && !modem->voiceService()) {
  777.         traceStatus(FAXTRACE_SERVER,
  778.         "ANSWER: Could not switch modem to voice service");
  779.         break;
  780.     }
  781.     // XXX setup voice process a la getty
  782.     break;
  783.     case FaxModem::CALLTYPE_ERROR:
  784.     traceStatus(FAXTRACE_SERVER, "ANSWER: %s", (char*) emsg);
  785.     break;
  786.     }
  787.     return (callSetup);
  788. }
  789.  
  790. /*
  791.  * Startup a getty process in response to a data connection.
  792.  * The speed parameter is passed to getty to use in establishing
  793.  * a login session.
  794.  */
  795. fxBool
  796. FaxServer::runGetty(const char* args)
  797. {
  798.     fxStr prefix(DEV_PREFIX);
  799.     fxStr dev(modemDevice);
  800.     if (dev.head(prefix.length()) == prefix)
  801.     dev.remove(0, prefix.length());
  802.     getty = OSnewGetty(dev, fxStr((int) baudRates[curRate], "%u"));
  803.     if (!getty) {
  804.     traceStatus(FAXTRACE_SERVER, "GETTY: could not create");
  805.     return (FALSE);
  806.     }
  807.     pid_t pid = fork();
  808.     if (pid == -1) {
  809.     traceStatus(FAXTRACE_SERVER, "GETTY: can not fork");
  810.     return (FALSE);
  811.     }
  812.     if (pid == 0) {
  813.     setProcessPriority(BASE);        // remove any high priority
  814.     if (setegid(getgid()) < 0)
  815.         traceStatus(FAXTRACE_SERVER, "runGetty::setegid: %m");
  816.     if (seteuid(getuid()) < 0)
  817.         traceStatus(FAXTRACE_SERVER, "runGetty::seteuid: %m");
  818.     getty->run(modemFd, args);
  819.     _exit(127);
  820.     /*NOTREACHED*/
  821.     } else {
  822.     traceStatus(FAXTRACE_SERVER, "GETTY: start pid %u, \"%s\"",
  823.        pid, args);
  824.     getty->setPID(pid);
  825.     /*
  826.      * Purge existing modem state because the getty+login processed
  827.      * will change everything and because we must close the descriptor
  828.      * so that the getty will get SIGHUP on last close.
  829.      */
  830.     discardModem(FALSE);
  831.     changeState(GETTYWAIT);
  832.     Dispatcher::instance().startChild(pid, this);
  833.     return (TRUE);
  834.     }
  835. }
  836.  
  837. void
  838. FaxServer::setDialRules(const char* name)
  839. {
  840.     if (dialRules)
  841.     delete dialRules, dialRules = NULL;
  842.     dialRules = new DialStringRules(name);
  843.     /*
  844.      * Setup configuration environment.
  845.      */
  846.     dialRules->def("AreaCode", myAreaCode);
  847.     dialRules->def("CountryCode", myCountryCode);
  848.     dialRules->def("LongDistancePrefix", longDistancePrefix);
  849.     dialRules->def("InternationalPrefix", internationalPrefix);
  850.     if (!dialRules->parse())
  851.     traceStatus(FAXTRACE_SERVER,
  852.         "Parse error in dial string rules \"%s\"", name);
  853. }
  854.  
  855. /*
  856.  * Convert a dialing string to a canonical format.
  857.  */
  858. fxStr
  859. FaxServer::canonicalizePhoneNumber(const fxStr& ds)
  860. {
  861.     if (dialRules)
  862.     return dialRules->canonicalNumber(ds);
  863.     else
  864.     return ds;
  865. }
  866.  
  867. /*
  868.  * Prepare a dialing string for use.
  869.  */
  870. fxStr
  871. FaxServer::prepareDialString(const fxStr& ds)
  872. {
  873.     if (dialRules)
  874.     return dialRules->dialString(ds);
  875.     else
  876.     return ds;
  877. }
  878.  
  879. /*
  880.  * Modem support interfaces.  Note that the values
  881.  * returned when we don't have a handle on the modem
  882.  * are selected so that any imaged facsimile should
  883.  * still be sendable.
  884.  */
  885. fxBool FaxServer::modemReady() const
  886.     { return modem != NULL; }
  887. fxBool FaxServer::modemSupports2D() const
  888.     { return modem ? modem->supports2D() : FALSE; }
  889. fxBool FaxServer::modemSupportsEOLPadding() const
  890.     { return modem ? modem->supportsEOLPadding() : FALSE; }
  891. fxBool FaxServer::modemSupportsVRes(float res) const
  892.     { return modem ? modem->supportsVRes(res) : TRUE; }
  893. fxBool FaxServer::modemSupportsPageWidth(u_int w) const
  894.     { return modem ? modem->supportsPageWidth(w) : TRUE; }
  895. fxBool FaxServer::modemSupportsPageLength(u_int l) const
  896.     { return modem ? modem->supportsPageLength(l) : TRUE; }
  897.  
  898. fxBool FaxServer::serverBusy() const
  899.     { return state != RUNNING; }
  900.  
  901. /*
  902.  * FaxServer configuration and query methods.
  903.  */
  904.  
  905. void
  906. FaxServer::setModemNumber(const fxStr& number)
  907. {
  908.     FAXNumber = number;
  909.     if (modem)
  910.     modem->setLID(canonicalizePhoneNumber(number));
  911. }
  912. const fxStr& FaxServer::getModemNumber()    { return (FAXNumber); }
  913.  
  914. void FaxServer::setServerTracing(int level)    { tracingLevel = level; }
  915. int FaxServer::getServerTracing()        { return (tracingLevel); }
  916. void FaxServer::setSessionTracing(int level)    { logTracingLevel = level; }
  917. int FaxServer::getSessionTracing()        { return (logTracingLevel); }
  918.  
  919. void
  920. FaxServer::setRingsBeforeAnswer(int rings)
  921. {
  922.     ringsBeforeAnswer = rings;
  923.     if (modem) {
  924.     IOHandler* h =
  925.         Dispatcher::instance().handler(modemFd, Dispatcher::ReadMask);
  926.     if (rings > 0 && h == NULL)
  927.         Dispatcher::instance().link(modemFd, Dispatcher::ReadMask, this);
  928.     else if (rings == 0 && h != NULL)
  929.         Dispatcher::instance().unlink(modemFd);
  930.     }
  931. }
  932. int FaxServer::getRingsBeforeAnswer()        { return (ringsBeforeAnswer); }
  933.  
  934. void
  935. FaxServer::setModemSpeakerVolume(SpeakerVolume lev)
  936. {
  937.     speakerVolume = lev;
  938.     if (modem)
  939.     modem->setSpeakerVolume(lev);
  940. }
  941. SpeakerVolume FaxServer::getModemSpeakerVolume(){ return (speakerVolume); }
  942.  
  943. static SpeakerVolume
  944. getVol(const char* cp)
  945. {
  946.     return (strcasecmp(cp, "off") == 0     ? FaxModem::OFF :
  947.         strcasecmp(cp, "quiet") == 0 ? FaxModem::QUIET :
  948.         strcasecmp(cp, "low") == 0     ? FaxModem::LOW :
  949.         strcasecmp(cp, "medium") == 0? FaxModem::MEDIUM :
  950.         strcasecmp(cp, "high") == 0     ? FaxModem::HIGH :
  951.                        (SpeakerVolume) atoi(cp));
  952. }
  953.  
  954. fxBool
  955. FaxServer::restoreState(const fxStr& filename)
  956. {
  957.     fxBool didSomething = FALSE;
  958.     FILE* fd = fopen(filename, "r");
  959.     if (fd) {
  960.     struct stat sb;
  961.     if (fstat(fileno(fd), &sb) >= 0 && sb.st_mtime != lastConfigModTime) {
  962.         char line[512];
  963.         while (fgets(line, sizeof (line)-1, fd))
  964.         restoreStateItem(line);
  965.         lastConfigModTime = sb.st_mtime;
  966.         didSomething = TRUE;
  967.     }
  968.     fclose(fd);
  969.     }
  970.     return (didSomething);
  971. }
  972.  
  973. static int
  974. getnum(const char* s)
  975. {
  976.     return ((int) strtol(s, NULL, 0));
  977. }
  978.  
  979. static fxBool
  980. getbool(const char* cp)
  981. {
  982.     return (streq(cp, "on") || streq(cp, "yes"));
  983. }
  984.  
  985. /*
  986.  * Process an answer rotary spec string.
  987.  */
  988. void
  989. FaxServer::setAnswerRotary(const fxStr& value)
  990. {
  991.     u_int l = 0;
  992.     for (u_int i = 0; i < 3 && l < value.length(); i++) {
  993.     fxStr type(value.token(l, " \t"));
  994.     type.raisecase();
  995.     if (type == "FAX")
  996.         answerRotary[i] = FaxModem::ANSTYPE_FAX;
  997.     else if (type == "DATA")
  998.         answerRotary[i] = FaxModem::ANSTYPE_DATA;
  999.     else if (type == "VOICE")
  1000.         answerRotary[i] = FaxModem::ANSTYPE_VOICE;
  1001.     else {
  1002.         if (type != "ANY")
  1003.         traceStatus(FAXTRACE_SERVER,
  1004.             "Unknown answer type \"%s\"", (char*) type);
  1005.         answerRotary[i] = FaxModem::ANSTYPE_ANY;
  1006.     }
  1007.     }
  1008.     if (i == 0)                // void string
  1009.     answerRotary[i++] = FaxModem::ANSTYPE_ANY;
  1010.     answerRotor = 0;
  1011.     answerRotorSize = i;
  1012. }
  1013.  
  1014. void
  1015. FaxServer::restoreStateItem(const char* b)
  1016. {
  1017.     char buf[512];
  1018.     char* cp;
  1019.  
  1020.     strncpy(buf, b, sizeof (buf));
  1021.     for (cp = buf; isspace(*cp); cp++)        // skip leading white space
  1022.     ;
  1023.     if (*cp == '#')
  1024.     return;
  1025.     const char* tag = cp;            // start of tag
  1026.     while (*cp && *cp != ':') {            // skip to demarcating ':'
  1027.     if (isupper(*cp))
  1028.         *cp = tolower(*cp);
  1029.     cp++;
  1030.     }
  1031.     if (*cp != ':') {
  1032.     traceStatus(FAXTRACE_SERVER, "Syntax error, missing ':' in \"%s\"", b);
  1033.     return;
  1034.     }
  1035.     for (*cp++ = '\0'; isspace(*cp); cp++)    // skip white space again
  1036.     ;
  1037.     const char* value;
  1038.     if (*cp == '"') {                // "..." value
  1039.     int c;
  1040.     /*
  1041.      * Parse quoted string and deal with \ escapes.
  1042.      */
  1043.     char* dp = ++cp;
  1044.     for (value = dp; (c = *cp) != '"'; cp++) {
  1045.         if (c == '\0') {            // unmatched quote mark
  1046.         traceStatus(FAXTRACE_SERVER,
  1047.             "Syntax error, missing quote mark in \"%s\"", b);
  1048.         return;
  1049.         }
  1050.         if (c == '\\') {
  1051.         c = *++cp;
  1052.         if (isdigit(c)) {        // \nnn octal escape
  1053.             int v = c - '0';
  1054.             if (isdigit(c = cp[1])) {
  1055.             cp++, v = (v << 3) + (c - '0');
  1056.             if (isdigit(c = cp[1]))
  1057.                 cp++, v = (v << 3) + (c - '0');
  1058.             }
  1059.             c = v;
  1060.         } else {            // \<char> escapes
  1061.             for (const char* tp = "n\nt\tr\rb\bf\fv\013"; *tp; tp += 2)
  1062.             if (c == tp[0]) {
  1063.                 c = tp[1];
  1064.                 break;
  1065.             }
  1066.         }
  1067.         }
  1068.         *dp++ = c;
  1069.     }
  1070.     *dp = '\0';
  1071.     } else {                    // value up to 1st non-ws
  1072.     for (value = cp; *cp && !isspace(*cp); cp++)
  1073.         ;
  1074.     *cp = '\0';
  1075.     }
  1076.     if (streq(tag, "recvfilemode"))    
  1077.     recvFileMode = (mode_t) strtol(value, 0, 8);
  1078.     else if (streq(tag, "devicemode"))    
  1079.     deviceMode = (mode_t) strtol(value, 0, 8);
  1080.     else if (streq(tag, "logfilemode"))    
  1081.     logMode = (mode_t) strtol(value, 0, 8);
  1082.     else if (streq(tag, "ringsbeforeanswer"))
  1083.     setRingsBeforeAnswer(getnum(value));
  1084.     else if (streq(tag, "speakervolume"))
  1085.     setModemSpeakerVolume(getVol(value));
  1086.     else if (streq(tag, "protocoltracing"))
  1087.     tracingLevel = logTracingLevel = getnum(value) &~ tracingMask;
  1088.     else if (streq(tag, "servertracing"))
  1089.     tracingLevel = getnum(value) &~ tracingMask;
  1090.     else if (streq(tag, "sessiontracing"))
  1091.     logTracingLevel = getnum(value) &~ tracingMask;
  1092.     else if (streq(tag, "faxnumber"))        setModemNumber(value);
  1093.     else if (streq(tag, "areacode"))        myAreaCode = value;
  1094.     else if (streq(tag, "countrycode"))        myCountryCode = value;
  1095.     else if (streq(tag, "longdistanceprefix"))    longDistancePrefix = value;
  1096.     else if (streq(tag, "internationalprefix"))    internationalPrefix = value;
  1097.     else if (streq(tag, "dialstringrules"))    setDialRules(value);
  1098.     else if (streq(tag, "qualifytsi"))        qualifyTSI = value;
  1099.     else if (streq(tag, "gettyspeed"))        gettyArgs = value;
  1100.     else if (streq(tag, "gettyargs"))        gettyArgs = value;
  1101.     else if (streq(tag, "nocarrierretrys"))    noCarrierRetrys = getnum(value);
  1102.     else if (streq(tag, "adaptiveanswer"))    adaptiveAnswer = getbool(value);
  1103.     else if (streq(tag, "answerrotary"))    setAnswerRotary(value);
  1104.     else if (streq(tag, "answerbias"))
  1105.     answerBias = fxmin(getnum(value),2);
  1106.     else if (streq(tag, "uucplocktimeout"))
  1107.     UUCPLock::setLockTimeout(getnum(value));
  1108.     else if (streq(tag, "jobreqbusy"))
  1109.     requeueTTS[FaxModem::BUSY] = getnum(value);
  1110.     else if (streq(tag, "jobreqnocarrier"))
  1111.     requeueTTS[FaxModem::NOCARRIER] = getnum(value);
  1112.     else if (streq(tag, "jobreqnoanswer"))
  1113.     requeueTTS[FaxModem::NOANSWER] = getnum(value);
  1114.     else if (streq(tag, "jobreqproto"))
  1115.     requeueProto = getnum(value);
  1116.     else if (streq(tag, "jobreqother"))
  1117.     requeueOther = getnum(value);
  1118.     else if (streq(tag, "pollmodemwait"))
  1119.     pollModemWait = getnum(value);
  1120.     else if (streq(tag, "polllockwait"))
  1121.     pollLockWait = getnum(value);
  1122.     else if (!modemConfig.parseItem(tag, value))
  1123.     traceStatus(FAXTRACE_SERVER,
  1124.         "Unknown configuration parameter \"%s\" ignored", b);
  1125. }
  1126.  
  1127. void
  1128. FaxServer::traceStatus(int kind, const char* va_alist ...)
  1129. #define    fmt va_alist
  1130. {
  1131.     va_list ap;
  1132.     va_start(ap, fmt);
  1133.     vtraceStatus(kind, fmt, ap);
  1134.     va_end(ap);
  1135. }
  1136. #undef fmt
  1137.  
  1138. #include "faxServerApp.h"
  1139.  
  1140. void
  1141. FaxServer::vtraceStatus(int kind, const char* fmt, va_list ap)
  1142. {
  1143.     if (log) {
  1144.     if (kind == FAXTRACE_SERVER)    // always log server stuff
  1145.         app->vlogInfo(fmt, ap);
  1146.     if (logTracingLevel & kind)
  1147.         log->vlog(fmt, ap);
  1148.     } else if (tracingLevel & kind)
  1149.     app->vlogInfo(fmt, ap);
  1150. }
  1151.  
  1152. #include "StackBuffer.h"
  1153.  
  1154. void
  1155. FaxServer::traceModemIO(const char* dir, const u_char* data, u_int cc)
  1156. {
  1157.     if (log) {
  1158.     if ((logTracingLevel& FAXTRACE_MODEMIO) == 0)
  1159.         return;
  1160.     } else if ((tracingLevel & FAXTRACE_MODEMIO) == 0)
  1161.     return;
  1162.  
  1163.     const char* hexdigits = "0123456789ABCDEF";
  1164.     fxStackBuffer buf;
  1165.     for (u_int i = 0; i < cc; i++) {
  1166.     u_char b = data[i];
  1167.     if (i > 0)
  1168.         buf.put(' ');
  1169.     buf.put(hexdigits[b>>4]);
  1170.     buf.put(hexdigits[b&0xf]);
  1171.     }
  1172.     traceStatus(FAXTRACE_MODEMIO, "%s <%u:%.*s>",
  1173.     dir, cc, buf.getLength(), (char*) buf);
  1174. }
  1175.  
  1176. #ifndef B38400
  1177. #define    B38400    B19200
  1178. #endif
  1179. #ifndef B57600
  1180. #define    B57600    B38400
  1181. #endif
  1182. #ifndef B76800
  1183. #define    B76800    B57600
  1184. #endif
  1185. static u_int termioBaud[] = {
  1186.     B0,        // BR0
  1187.     B300,    // BR300
  1188.     B1200,    // BR1200
  1189.     B2400,    // BR2400
  1190.     B4800,    // BR4800
  1191.     B9600,    // BR9600
  1192.     B19200,    // BR19200
  1193.     B38400,    // BR38400
  1194.     B57600,    // BR57600
  1195.     B76800,    // BR76800
  1196. };
  1197. #define    NBAUDS    (sizeof (termioBaud) / sizeof (termioBaud[0]))
  1198. static const char* flowNames[] =
  1199.     { "NONE", "CURRENT", "XON/XOFF", "RTS/CTS", };
  1200.  
  1201. #ifdef __bsdi__
  1202. #undef    CRTSCTS
  1203. #define    CRTSCTS    (CCTS_OFLOW|CRTS_IFLOW)
  1204. #endif
  1205. #ifndef CRTSCTS
  1206. #ifdef CNEW_RTSCTS            /* XXX IRIX 5.x botch */
  1207. #define    CRTSCTS    CNEW_RTSCTS
  1208. #else
  1209. #define    CRTSCTS    0
  1210. #endif
  1211. #endif
  1212.  
  1213. static void
  1214. setFlow(termios& term, FlowControl iflow, FlowControl oflow)
  1215. {
  1216.     switch (iflow) {
  1217.     case FaxModem::FLOW_CURRENT:
  1218.     break;
  1219.     case FaxModem::FLOW_NONE:
  1220.     term.c_iflag &= ~IXON;
  1221.     term.c_cflag &= ~CRTSCTS;
  1222.     break;
  1223.     case FaxModem::FLOW_XONXOFF:
  1224.     term.c_iflag |= IXON;
  1225.     term.c_cflag &= ~CRTSCTS;
  1226.     break;
  1227.     case FaxModem::FLOW_RTSCTS:
  1228.     term.c_iflag &= ~IXON;
  1229.     term.c_cflag |= CRTSCTS;
  1230.     break;
  1231.     }
  1232.     switch (oflow) {
  1233.     case FaxModem::FLOW_CURRENT:
  1234.     break;
  1235.     case FaxModem::FLOW_NONE:
  1236.     term.c_iflag &= ~IXOFF;
  1237.     term.c_cflag &= ~CRTSCTS;
  1238.     break;
  1239.     case FaxModem::FLOW_XONXOFF:
  1240.     term.c_iflag |= IXOFF;
  1241.     term.c_cflag &= ~CRTSCTS;
  1242.     break;
  1243.     case FaxModem::FLOW_RTSCTS:
  1244.     term.c_iflag &= ~IXOFF;
  1245.     term.c_cflag |= CRTSCTS;
  1246.     break;
  1247.     }
  1248. }
  1249.  
  1250. /*
  1251.  * Device manipulation.
  1252.  */
  1253.  
  1254. /*
  1255.  * Set tty port baud rate and flow control.
  1256.  */
  1257. fxBool
  1258. FaxServer::setBaudRate(BaudRate rate, FlowControl iFlow, FlowControl oFlow)
  1259. {
  1260.     struct termios term;
  1261.     if (tcgetattr(modemFd, &term) == 0) {
  1262.     if (rate >= NBAUDS)
  1263.         rate = NBAUDS-1;
  1264.     curRate = rate;                // NB: for use elsewhere
  1265.     term.c_oflag = 0;
  1266.     term.c_lflag = 0;
  1267.     term.c_iflag &= IXON|IXOFF;        // keep these bits
  1268.     term.c_cflag &= CRTSCTS;        // and these bits
  1269.     setFlow(term, iFlow, oFlow);
  1270.     term.c_cflag |= CLOCAL | CS8 | CREAD;
  1271.     cfsetospeed(&term, termioBaud[rate]);
  1272.     cfsetispeed(&term, termioBaud[rate]);
  1273.     term.c_cc[VMIN] = 127;            // buffer input by default
  1274.     term.c_cc[VTIME] = 1;
  1275.     traceStatus(FAXTRACE_MODEMOPS,
  1276.         "MODEM set baud rate: %d baud, input flow %s, output flow %s",
  1277.         baudRates[rate], flowNames[iFlow], flowNames[oFlow]);
  1278.     flushModemInput();
  1279.     return (tcsetattr(modemFd, TCSAFLUSH, &term) == 0);
  1280.     } else
  1281.     return (FALSE);
  1282. }
  1283.  
  1284. /*
  1285.  * Set tty port baud rate and leave flow control state unchanged.
  1286.  */
  1287. fxBool
  1288. FaxServer::setBaudRate(BaudRate rate)
  1289. {
  1290.     struct termios term;
  1291.     if (tcgetattr(modemFd, &term) == 0) {
  1292.     if (rate >= NBAUDS)
  1293.         rate = NBAUDS-1;
  1294.     curRate = rate;                // NB: for use elsewhere
  1295.     term.c_oflag = 0;
  1296.     term.c_lflag = 0;
  1297.     term.c_iflag &= IXON|IXOFF;        // keep these bits
  1298.     term.c_cflag &= CRTSCTS;        // and these bits
  1299.     term.c_cflag |= CLOCAL | CS8 | CREAD;
  1300.     cfsetospeed(&term, termioBaud[rate]);
  1301.     cfsetispeed(&term, termioBaud[rate]);
  1302.     term.c_cc[VMIN] = 127;            // buffer input by default
  1303.     term.c_cc[VTIME] = 1;
  1304.     traceStatus(FAXTRACE_MODEMOPS,
  1305.         "MODEM set baud rate: %d baud (flow control unchanged)",
  1306.         baudRates[rate]);
  1307.     flushModemInput();
  1308.     return (tcsetattr(modemFd, TCSAFLUSH, &term) == 0);
  1309.     } else
  1310.     return (FALSE);
  1311. }
  1312.  
  1313. /*
  1314.  * Manipulate DTR on tty port.
  1315.  *
  1316.  * On systems that support explicit DTR control this is done
  1317.  * with an ioctl.  Otherwise we assume that setting the baud
  1318.  * rate to zero causes DTR to be dropped (asserting DTR is
  1319.  * assumed to be implicit in setting a non-zero baud rate).
  1320.  *
  1321.  * NB: we use the explicit DTR manipulation ioctls because
  1322.  *     setting the baud rate to zero on some systems can cause
  1323.  *     strange side effects.
  1324.  */
  1325. fxBool
  1326. FaxServer::setDTR(fxBool onoff)
  1327. {
  1328.     traceStatus(FAXTRACE_MODEMOPS, "MODEM set DTR %s", onoff ? "ON" : "OFF");
  1329. #ifdef TIOCMBIS
  1330.     int mctl = TIOCM_DTR;
  1331. #ifdef sun
  1332.     /*
  1333.      * Happy days! SVR4 passes the arg by value, while
  1334.      * SunOS 4.x passes it by reference; is this progress?
  1335.      */
  1336.     if (ioctl(modemFd, onoff ? TIOCMBIS : TIOCMBIC, (char *)&mctl) == 0)
  1337. #else
  1338.     if (ioctl(modemFd, onoff ? TIOCMBIS : TIOCMBIC, (char *)mctl) == 0)
  1339. #endif
  1340.     return (TRUE);
  1341.     /*
  1342.      * Sigh, Sun seems to support this ioctl only on *some*
  1343.      * devices (e.g. on-board duarts, but not the ALM-2 card);
  1344.      * so if the ioctl that should work fails, we fallback
  1345.      * on the usual way of doing things...
  1346.      */
  1347. #endif
  1348.     return (onoff ? TRUE : setBaudRate(FaxModem::BR0));
  1349. }
  1350.  
  1351. static const char* actNames[] = { "NOW", "DRAIN", "FLUSH" };
  1352. static u_int actCode[] = { TCSANOW, TCSADRAIN, TCSAFLUSH };
  1353.  
  1354. /*
  1355.  * Set tty modes so that the specified handling
  1356.  * is done on data being sent and received.  When
  1357.  * transmitting binary data, oFlow is FLOW_NONE to
  1358.  * disable the transmission of XON/XOFF by the host
  1359.  * to the modem.  When receiving binary data, iFlow
  1360.  * is FLOW_NONE to cause XON/XOFF from the modem
  1361.  * to not be interpreted.  In each case the opposite
  1362.  * XON/XOFF handling should be enabled so that any
  1363.  * XON/XOFF from/to the modem will be interpreted.
  1364.  */
  1365. fxBool
  1366. FaxServer::setXONXOFF(FlowControl iFlow, FlowControl oFlow, SetAction act)
  1367. {
  1368.     struct termios term;
  1369.     if (tcgetattr(modemFd, &term) == 0) {
  1370.     setFlow(term, iFlow, oFlow);
  1371.     traceStatus(FAXTRACE_MODEMOPS,
  1372.         "MODEM set XON/XOFF/%s: input %s, output %s",
  1373.         actNames[act],
  1374.         iFlow == FaxModem::FLOW_NONE ? "disabled" : "enabled",
  1375.         oFlow == FaxModem::FLOW_NONE ? "disabled" : "enabled"
  1376.     );
  1377.     if (act == FaxModem::ACT_FLUSH)
  1378.         flushModemInput();
  1379.     if (tcsetattr(modemFd, actCode[act], &term) == 0)
  1380.         return (TRUE);
  1381.     }
  1382.     return (FALSE);
  1383. }
  1384.  
  1385. #ifdef sgi
  1386. #include <sys/stropts.h>
  1387. #include <sys/z8530.h>
  1388. #endif
  1389. #ifdef sun
  1390. #include <sys/stropts.h>
  1391. #endif
  1392.  
  1393. /*
  1394.  * Setup process state either for minimum latency (no buffering)
  1395.  * or reduced latency (input may be buffered).  We fiddle with
  1396.  * the termio structure and, if required, the streams timer
  1397.  * that delays the delivery of input data from the UART module
  1398.  * upstream to the tty module.
  1399.  */
  1400. fxBool
  1401. FaxServer::setInputBuffering(fxBool on)
  1402. {
  1403.     traceStatus(FAXTRACE_MODEMOPS, "MODEM input buffering %s",
  1404.     on ? "enabled" : "disabled");
  1405. #ifdef SIOC_ITIMER
  1406.     /*
  1407.      * Silicon Graphics systems have a settable timer
  1408.      * that causes the UART driver to delay passing
  1409.      * data upstream to the tty module.  This can cause
  1410.      * anywhere from 20-30ms delay between input characters.
  1411.      * We set it to zero when input latency is critical.
  1412.      */
  1413.     strioctl str;
  1414.     str.ic_cmd = SIOC_ITIMER;
  1415.     str.ic_timout = (on ? 2 : 0);    // 2 ticks = 20ms (usually)
  1416.     str.ic_len = 4;
  1417.     int arg = 0;
  1418.     str.ic_dp = (char*)&arg;
  1419.     if (ioctl(modemFd, I_STR, &str) < 0)
  1420.     traceStatus(FAXTRACE_MODEMOPS, "MODEM ioctl(SIOC_ITIMER): %m");
  1421. #endif
  1422. #ifdef sun
  1423.     /*
  1424.      * SunOS has a timer similar to the SIOC_ITIMER described
  1425.      * above for input on the on-board serial ports, but it is
  1426.      * not generally accessible because it is controlled by a
  1427.      * stream control message (M_CTL w/ either MC_SERVICEDEF or
  1428.      * MC_SERVICEIMM) and you can not do a putmsg directly to
  1429.      * the UART module and the tty driver does not provide an
  1430.      * interface.  Also, the ALM-2 driver apparently also has
  1431.      * a timer, but does not provide the M_CTL interface that's
  1432.      * provided for the on-board ports.  All in all this means
  1433.      * that the only way to defeat the timer for the on-board
  1434.      * serial ports (and thereby provide enough control for the
  1435.      * fax server to work with Class 1 modems) is to implement
  1436.      * a streams module in the kernel that provides an interface
  1437.      * to the timer--which is what has been done.  In the case of
  1438.      * the ALM-2, however, you are just plain out of luck unless
  1439.      * you have source code.
  1440.      */
  1441.     static fxBool zsunbuf_push_tried = FALSE;
  1442.     static fxBool zsunbuf_push_ok = FALSE;
  1443.     if (on) {            // pop zsunbuf if present to turn on buffering
  1444.     char topmodule[FMNAMESZ+1];
  1445.         if (zsunbuf_push_ok && ioctl(modemFd, I_LOOK, topmodule) >= 0 &&
  1446.       streq(topmodule, "zsunbuf")) {
  1447.         if (ioctl(modemFd, I_POP, 0) < 0)
  1448.         traceStatus(FAXTRACE_MODEMOPS, "MODEM pop zsunbuf failed %m");
  1449.     }
  1450.     } else {            // push zsunbuf to turn off buffering
  1451.         if (!zsunbuf_push_tried) {
  1452.             zsunbuf_push_ok = (ioctl(modemFd, I_PUSH, "zsunbuf") >= 0);
  1453.             traceStatus(FAXTRACE_MODEMOPS, "MODEM initial push zsunbuf %s",
  1454.                 zsunbuf_push_ok ? "succeeded" : "failed");
  1455.             zsunbuf_push_tried = TRUE;
  1456.         } else if (zsunbuf_push_ok) {
  1457.             if (ioctl(modemFd, I_PUSH, "zsunbuf") < 0)
  1458.                 traceStatus(FAXTRACE_MODEMOPS, "MODEM push zsunbuf failed %m");
  1459.         }
  1460.     }
  1461. #endif
  1462.     struct termios term;
  1463.     (void) tcgetattr(modemFd, &term);
  1464.     if (on) {
  1465.     term.c_cc[VMIN] = 127;
  1466.     term.c_cc[VTIME] = 1;
  1467.     } else {
  1468.     term.c_cc[VMIN] = 1;
  1469.     term.c_cc[VTIME] = 0;
  1470.     }
  1471.     return (tcsetattr(modemFd, TCSANOW, &term) == 0);
  1472. }
  1473.  
  1474. fxBool
  1475. FaxServer::sendBreak(fxBool pause)
  1476. {
  1477.     traceStatus(FAXTRACE_MODEMOPS, "MODEM send break");
  1478.     flushModemInput();
  1479.     if (pause) {
  1480.     /*
  1481.      * NB: TCSBRK is supposed to wait for output to drain,
  1482.      * but modem appears loses data if we don't do this.
  1483.      */
  1484.     (void) tcdrain(modemFd);
  1485.     }
  1486.     return (tcsendbreak(modemFd, 0) == 0);
  1487. }
  1488.  
  1489. static fxBool timerExpired = FALSE;
  1490. static void sigAlarm(int)        { timerExpired = TRUE; }
  1491.  
  1492. #ifndef SA_INTERRUPT
  1493. #define    SA_INTERRUPT    0
  1494. #endif
  1495.  
  1496. void
  1497. FaxServer::startTimeout(long ms)
  1498. {
  1499.     timeout = ::timerExpired = FALSE;
  1500. #ifdef SV_INTERRUPT            /* BSD-style */
  1501.     static struct sigvec sv;
  1502.     sv.sv_handler = fxSIGVECHANDLER(sigAlarm);
  1503.     sv.sv_flags = SV_INTERRUPT;
  1504.     sigvec(SIGALRM, &sv, (struct sigvec*) 0);
  1505. #else
  1506. #ifdef SA_NOCLDSTOP            /* POSIX */
  1507.     static struct sigaction sa;
  1508.     sa.sa_handler = fxSIGACTIONHANDLER(sigAlarm);
  1509.     sa.sa_flags = SA_INTERRUPT;
  1510.     sigaction(SIGALRM, &sa, (struct sigaction*) 0);
  1511. #else                    /* System V-style */
  1512.     signal(SIGALRM, fxSIGHANDLER(sigAlarm));
  1513. #endif
  1514. #endif
  1515. #ifdef ITIMER_REAL
  1516.     itimerval itv;
  1517.     itv.it_value.tv_sec = ms / 1000;
  1518.     itv.it_value.tv_usec = (ms % 1000) * 1000;
  1519.     timerclear(&itv.it_interval);
  1520.     (void) setitimer(ITIMER_REAL, &itv, (itimerval*) 0);
  1521.     traceStatus(FAXTRACE_TIMEOUTS, "START %ld.%02ld second timeout",
  1522.     itv.it_value.tv_sec, itv.it_value.tv_usec / 10000);
  1523. #else
  1524.     long secs = howmany(ms, 1000);
  1525.     (void) alarm(secs);
  1526.     traceStatus(FAXTRACE_TIMEOUTS, "START %ld second timeout", secs);
  1527. #endif
  1528. }
  1529.  
  1530. void
  1531. FaxServer::stopTimeout(const char* whichdir)
  1532. {
  1533. #ifdef ITIMER_REAL
  1534.     static itimerval itv = { 0, 0, 0, 0 };
  1535.     (void) setitimer(ITIMER_REAL, &itv, (itimerval*) 0);
  1536. #else
  1537.     (void) alarm(0);
  1538. #endif
  1539.     traceStatus(FAXTRACE_TIMEOUTS,
  1540.     "STOP timeout%s", ::timerExpired ? ", timer expired" : "");
  1541.     if (timeout = ::timerExpired)
  1542.     traceStatus(FAXTRACE_MODEMOPS, "TIMEOUT: %s", whichdir);
  1543. }
  1544.  
  1545. int
  1546. FaxServer::getModemLine(char rbuf[], u_int bufSize, long ms)
  1547. {
  1548.     int c;
  1549.     int cc = 0;
  1550.     if (ms) startTimeout(ms);
  1551.     do {
  1552.     while ((c = getModemChar(0)) != EOF && c != '\n')
  1553.         if (c != '\0' && c != '\r' && cc < bufSize)
  1554.         rbuf[cc++] = c;
  1555.     } while (cc == 0 && c != EOF);
  1556.     rbuf[cc] = '\0';
  1557.     if (ms) stopTimeout("reading line from modem");
  1558.     if (!timeout)
  1559.     traceStatus(FAXTRACE_MODEMCOM, "--> [%d:%s]", cc, rbuf);
  1560.     return (cc);
  1561. }
  1562.  
  1563. int
  1564. FaxServer::getModemChar(long ms)
  1565. {
  1566.     if (rcvNext >= rcvCC) {
  1567.     int n = 0;
  1568.     if (ms) startTimeout(ms);
  1569.     do
  1570.         rcvCC = ::read(modemFd, rcvBuf, sizeof (rcvBuf));
  1571.     while (n++ < 5 && rcvCC == 0);
  1572.     if (ms) stopTimeout("reading from modem");
  1573.     if (rcvCC <= 0) {
  1574.         if (rcvCC < 0) {
  1575.         if (errno != EINTR)
  1576.             traceStatus(FAXTRACE_MODEMOPS,
  1577.             "Error #%u reading from modem", errno);
  1578.         }
  1579.         return (EOF);
  1580.     } else
  1581.         traceModemIO("-->", rcvBuf, rcvCC);
  1582.     rcvNext = 0;
  1583.     }
  1584.     return (rcvBuf[rcvNext++]);
  1585. }
  1586.  
  1587. void
  1588. FaxServer::modemFlushInput()
  1589. {
  1590.     flushModemInput();
  1591.     (void) tcflush(modemFd, TCIFLUSH);
  1592.     traceStatus(FAXTRACE_MODEMOPS, "MODEM flush i/o");
  1593. }
  1594.  
  1595. fxBool
  1596. FaxServer::modemStopOutput()
  1597. {
  1598.     return (tcflow(modemFd, TCOOFF) == 0);
  1599. }
  1600.  
  1601. void
  1602. FaxServer::flushModemInput()
  1603. {
  1604.     rcvCC = rcvNext = 0;
  1605. }
  1606.  
  1607. fxBool
  1608. FaxServer::putModem(const void* data, int n, long ms)
  1609. {
  1610.     traceStatus(FAXTRACE_MODEMCOM, "<-- data [%d]", n);
  1611.     return (putModem1(data, n, ms));
  1612. }
  1613.  
  1614. fxBool
  1615. FaxServer::putModem1(const void* data, int n, long ms)
  1616. {
  1617.     if (ms)
  1618.     startTimeout(ms);
  1619.     else
  1620.     timeout = FALSE;
  1621.     int cc = ::write(modemFd, (char*) data, n);
  1622.     if (ms)
  1623.     stopTimeout("writing to modem");
  1624.     if (cc > 0) {
  1625.     traceModemIO("<--", (const u_char*) data, cc);
  1626.     n -= cc;
  1627.     }
  1628.     return (!timeout && n == 0);
  1629. }
  1630.